//This file contains the logging middleware.
import 'package:copilot_proxy/check_auth/check_auth.dart';
import 'package:copilot_proxy/context.dart';
import 'package:copilot_proxy/middleware/middleware.dart';
import 'package:copilot_proxy/utils/utils.dart';

Future<void> loggingMiddleware(Context context, Next next) async {
  final start = DateTime.now();
  log('$start [${context.method}] ${context.path}');
  log('requestedUri: ${context.request.requestedUri}', false);
  log('headers: ${jsonPretty(context.request.headers.toFullMap())}', false);
  try {
    await next();
  } catch (e) {
    rethrow;
  } finally {
    final end = DateTime.now();
    final time = end.difference(start).inMilliseconds;
    final token = context['token'];
    final clientIP = context['cf-connecting-ip'] ?? context['x-forwarded-for'];
    if (clientIP != null) log('clientIp: $clientIP');
    if (context.hasData) log('context: ${context.toLimitString()}');
    log('code: ${context.response.statusCode}, cost: ${time}ms\n');
    _bindClientIdToIP(token, clientIP);
  }
}

///记录每个clientId使用过的IP地址
final Map<String, List<String>> _clientIPs = {};

Future<void> saveClientIPs() => saveJson('client_ip.json', _clientIPs);

Future<void> loadClientIPs() async {
  final data = await loadJson('client_ip.json');
  if (data is! Map) return;
  _clientIPs.clear();
  for (final entry in data.entries) {
    final clientId = entry.key;
    final clientIPs = entry.value;
    if (clientIPs is! List) continue;
    _clientIPs[clientId] = List<String>.from(clientIPs);
  }
}

void _bindClientIdToIP(String? token, String? clientIP) {
  if (token == null || clientIP == null) return;
  String? clientId;
  if (isAccessTokenValid(token)) {
    clientId = getClientId(token);
  } else if (isCopilotTokenValid(token)) {
    clientId = getClientIdByCopilotToken(token);
  }
  if (clientId == null) return;
  final clientIPList = _clientIPs[clientId] ??= [];
  if (!clientIPList.contains(clientIP)) clientIPList.add(clientIP);
}

String? getClientIdByCopilotToken(String? copilotToken) {
  if (copilotToken == null) return null;
  final parts = copilotToken.split(';');
  for (final part in parts) {
    final kv = part.split('=');
    if (kv.length != 2) continue;
    final key = kv[0];
    final value = kv[1];
    if (key == 'cid') return value;
  }
  return null;
}
